import { observable, action, toJS} from 'mobx';
import EditorUtil from '../../util/ckextraEditorUtil';
import RangeUtil from '../../util/ckextraRangeUtil';
import {Modal, message} from 'antd';
import {WeaTools,WeaLocaleProvider} from 'ecCom';
import isFunction from 'lodash/isFunction';
import uniq from 'lodash/uniq';
const getLabel = WeaLocaleProvider.getLabel;

export default class Postil {
  @observable isEdit = false;
  @observable show = false;
  @observable list = [];// 批注列表，按id排序
  @observable text = '';
  @observable editItem = null;
  @observable editItemIndex = -1;
  @observable chooseItemIds = [];
  @observable textareaRef = null;

  @observable showCloseId = -1;

  @observable delModalVisible = false; // 删除弹框
  @observable delIds = []; // 记录删除的id
  @observable isDelPostil = false;
  @observable delPosModalVisible = false;
  @observable delPOstilIds = []; // 记录删除的id
  @observable delAll = false;
  @observable showRevision = false;
  isObserved = false;
  currentObserver;
  chooseChangeFuncList = [];//选中批注时的回调方法

  @action
  setState = (state) => {
    for (let key in state) {
      this[key] = state[key];
    }
  }
  createPostil = () => {
    let selectedText = EditorUtil.getSelectedText();
    if (!selectedText) {
      message.warning("请选中文字后再进行批注");
      // Modal.warning({
      //   title: '提示信息',
      //   content: '新建批注需要勾选文字！'
      // });
      return;
    }
    if (this.isEdit) return;
    this.show = true;
    this.isEdit = true;
    parent && typeof parent.changeDisplayAnnotations === 'function' && parent.changeDisplayAnnotations(true)

    // this.textareaRef && this.textareaRef.focus();
  }

  transcreatedElement = () => {
    const editor = EditorUtil.getEditor();
    const uDoms = editor.document.find('u').toArray();
    uDoms.forEach(udom => {
      const html = udom.getHtml();
      const postils = udom.find('postil').toArray();
      if (postils.length > 0) {
        if (html.indexOf('<postil') === 0) {
          const postilStart = postils[0];
          postilStart.insertBefore(udom);
        }
        if (html.lastIndexOf('</postil') === html.length - 9) {
          const postilEnd = postils[postils.length - 1];
          postilEnd.insertAfter(udom);
        }
      }
    });
  }

  save = () => {
    if (this.text === '') {
      message.warning("请输入批注内容");
      return ;
    }
    if (this.text) {
      const selectedText = EditorUtil.getSelectedText();
      let item = {
        author: CKEditorParams.author,
        datetime: WeaTools.formatRealDate(new Date(), 'yyyy-MM-dd HH:mm:ss'),
        text: this.text,
        selectedText,
      }, props = {...item};

      if (this.editItem) { // 编辑
        // 右侧显示处理
        item.id = this.editItem.id;
        props.dataId = item.id;
        this.list.splice(this.editItemIndex, 0, item);
        this.editItem = null;
        this.editItemIndex = -1;

        // 替换文本中之前批注的标签内容
        let editor = EditorUtil.getEditor(),
          nodes = editor.document.find(`postil[dataId='${item.id}']`);
        nodes.forEach((node) => node.setAttributes(props) )
      } else { // 新增
        item.id = this.generateId();
        props.dataId = item.id;
        this.list.push(item);

        // 向文本中插入批注标签记录
        let ranges = EditorUtil.getRanges(), editor = EditorUtil.getEditor();
        // 多个选中状态现在暂不处理
        if (ranges.length > 1 || ranges.length === 0) return;
        let range = ranges[0];
        let doc = range.document,
          postilStart = doc.createElement("postil", {attributes: {...props, type: 'start'}}),
          postilEnd = doc.createElement("postil", {attributes: {...props, type: 'end'}});
        range.optimizeBookmark();
        range.trim();
        let startContainer = range.startContainer, startOffset = range.startOffset, endContainer = range.endContainer, endOffset = range.endOffset;
        let startNode = startContainer.getChild(startOffset), endNode = endContainer.getChild(endOffset);
        startNode ? postilStart.insertBefore(startNode) : startContainer.append(postilStart);
        endNode ? postilEnd.insertBefore(endNode) : endContainer.append(postilEnd);
        // 修订模式下，postil标签与u标签相邻时，需把postil标签放到u标签外部
        if (this.showRevision) {
          this.transcreatedElement();
        }
        // 支持IE9.10
        postilStart.on('DOMNodeRemovedFromDocument', this.onDelPostilNode, null, {item, type: 'start'});
        postilEnd.on('DOMNodeRemovedFromDocument', this.onDelPostilNode, null, {item, type: 'end'});

        this.observeNodeChange();
      }
    }
    this.cancelEdit();
    EditorUtil.getEditor().undoManager.save();
    this.refreshPostil();
  }

  cancelEdit = () => {
    this.text = '';
    this.isEdit = false;
    if (this.editItem) {
      this.list.splice(this.editItemIndex, 0, this.editItem);
      this.editItem = null;
      this.editItemIndex = -1;
    }
    this.show = this.list.length > 0;
  }

  edit = (id) => {
    let itemIndex = this.list.findIndex((ele) => ele.id === id);
    if (itemIndex === -1)return;
    let item = this.list[itemIndex];
    if (this.isEdit && this.editItem) {
      this.cancelEdit();
    }
    this.text = item ? item.text : '';
    this.list = this.list.filter((ele) => ele.id !== id);
    this.editItem = item;
    this.editItemIndex = itemIndex;
    this.isEdit = true;
    this.show = true;
    // this.textareaRef && this.textareaRef.focus();
  }

  del = (ids, needDel = false) => {
    // if (!this.showRevision || this.canDel(ids)) {
    if (!this.showRevision || needDel) {
      ids.forEach((id) => {
        this.list = this.list.filter((item) => parseInt(item.id) !== parseInt(id));
        let editor = EditorUtil.getEditor(),
          startNodes = editor.document.find(`postil[type='start'][dataId='${id}']`),
          endNodes = editor.document.find(`postil[type='end'][dataId='${id}']`);
        startNodes.toArray().map((node) => node.remove());
        endNodes.toArray().map((node) => node.remove());
      });
      EditorUtil.getEditor().undoManager.save();
      this.delIds = [];
      this.delModalVisible = false;
    }
   }

  generateId = () => {
    if (!this.list || !this.list.length) {
      return 1;
    }
    let list = [...this.list].sort((first, second) => {
      return parseInt(first.id) - parseInt(second.id);
    });
    return parseInt(list[list.length - 1].id) + 1;
  }

  chooseItem = (id) => {
    this.chooseItemIds = [id];
    this.showCloseId = id;
    let editor = EditorUtil.getEditor(),
      startNodes = editor.document.find(`postil[type='start'][dataId='${id}']`),
      endNodes = editor.document.find(`postil[type='end'][dataId='${id}']`);
    if (startNodes.count() === 0 || endNodes.count() === 0) return;
    let startNode = startNodes.getItem(0), endNode = endNodes.getItem(endNodes.count() - 1);
    let range = editor.createRange();
    range.setStartAt( startNode, CKEDITOR.POSITION_AFTER_END );
    range.setEndAt( endNode, CKEDITOR.POSITION_BEFORE_START );
    editor.focus();
    editor.getSelection().selectRanges( [ range ] );
    startNode.scrollIntoView(true);
    this.chooseChangeFuncList.forEach((func) => func(id));
  }

  init = () => {
    let editor = EditorUtil.getEditor(), body = editor.document.getBody();
    body.on('click', this.refreshChooseStatus);
    body.on('keyup', this.refreshChooseStatus);
    body.on('compositionend', this.refreshChooseStatus);
    editor.on("afterCommandExec", (evt) => {
      const { name } = evt.data;
      if (name === 'undo' || name === 'redo') {
        this.refreshPostil();
      }
    });
  }
  
  lockUndo = () => {
    EditorUtil.getEditor().undoManager.lock();
  }

  unLockUndo = () => {
    EditorUtil.getEditor().undoManager.unlock();
  }
  refreshChooseStatus = (mustRefresh = false) => {
    //清除没有包含内容的批注
    this.list.forEach((ele) => {
      jQuery('postil[type="start"][dataid="' + ele.id + '"]').next;
    })
    if (!this.showRevision && !mustRefresh) this.refreshPostil();
    const editor = EditorUtil.getEditor();
    const ranges = editor.getSelection().getRanges();
    const range = ranges && ranges[0];
    if (range) {
      const oldRange = range && range.clone();
      //CKEDITOR的Range获取有BUG，使用原生的RANGE
      let htmlRange = new Range();
      editor.document.find('p').getItem(0) && htmlRange.setStartBefore(editor.document.find('p').getItem(0).$);
      oldRange && htmlRange.setEnd(oldRange.endContainer.$,oldRange.endOffset);
      let html = htmlRange.cloneContents();
      if(jQuery('#postil').find('#postilTemp').length <= 0){
        jQuery('#postil').append('<div id="postilTemp" style="display:none"></div>');
      }
      jQuery('#postilTemp').html(html);
      
      let tempchooseItemIds = [];
      var startPostilList = jQuery('#postilTemp').find('postil[type="start"]');
      for(var i = 0; i < startPostilList.length; i++){
        let ele = startPostilList[i];
        if(jQuery('#postilTemp').find('postil[type="end"][dataid="' + ele.getAttribute('dataid') + '"]').length <= 0){
          tempchooseItemIds.push(ele.getAttribute('dataid'));
        }
      }
      if (tempchooseItemIds.length === 0 && this.isEdit) this.isEdit = false;
      // 如果postil标签中包含的内容和selectText不匹配，则删除该批注
      this.lockUndo();
      const startContainer = range.startContainer, endContainer = range.endContainer;
      tempchooseItemIds.forEach((id) => {
        const dom = editor.document.find(`postil[type='start'][dataId='${id}']`).toArray();
        if (dom && dom.length > 0 && startContainer) {
          const valueA = dom[0].getAttribute('selectedText'), valueB = startContainer.getText();
          // 判断两个字符串中是否有相同的数据
          if (valueB.length > 0) {
            let isEqual = false;
            for (let i = 0; i < valueB.length; i++) {
              if (valueA.indexOf(valueB[i]) >= 0) {
                isEqual = true;
                break;
              }
            }
            // 内容完全不相同，则删除该批注
            if (!isEqual) {
              this.del([id]);
            }
          }
        }
      });
      this.unLockUndo();
      this.chooseItemIds = tempchooseItemIds;
    }
  }

  dodeleteAllPostil = () => {
    this.delAll = true;
    this.list = [];
    let editor = EditorUtil.getEditor(),
      nodes = editor.document.find('postil');
    if (!this.showRevision) {
      nodes.toArray().map((node) => node.remove());
    } else {
      const nodeIds = nodes.toArray().map((node) => node.getAttribute('dataid'));
      const needDelIds = this.getNeedDelIds(nodeIds);
      nodes.toArray().forEach((node) => {
        const id = node.getAttribute('dataid');
        if (needDelIds.indexOf(id) >= 0) node.remove();
        else this.addPostil([id]);
      });
      this.refreshPostil();
    }
    this.chooseChangeFuncList.forEach((func) => func());
    this.delPosModalVisible = false;
    this.delAll = false;
  }
  deleteAllPostil = () => {
    if (this.list.length === 0) {
      message.warning("暂无批注");
    } else {
      let editor = EditorUtil.getEditor(), nodes = editor.document.find('postil');
      const nodeIds = nodes.toArray().map((node) => node.getAttribute('dataid'));
      if (this.canDel(nodeIds)) {
        this.delPosModalVisible = true;
      } else {
        message.info("修订模式下，此批注不可删除");
      }
    }
  }

  doDeletePostil = (delPOstilIds = []) => {
    this.delPOstilIds = delPOstilIds;
    this.del(this.chooseItemIds, true);
    this.chooseItemIds = [];
    this.delPOstilIds = [];
    this.chooseChangeFuncList.forEach((func) => func());
    this.delPosModalVisible = false;
    this.isDelPostil = false;
  }
  deletePostil = () => {
    if (this.list.length === 0) {
      message.warning("暂无批注");
    } else if (this.chooseItemIds.length > 0) {
      const canDel = this.canDel(toJS(this.chooseItemIds));
      if (canDel) {
        this.isDelPostil = true;
        this.delPosModalVisible = true;
      } else {
        message.info("修订模式下，此批注不可删除");
      }
    } else {
      message.warning("请选择要删除的批注");
    }
  }
  getNeedDelIds = (chooseItemIds = []) => {
    let needDelIds = [];
    const editor = EditorUtil.getEditor();
    const nodes = editor.document.find('s').toArray();
    let sNodes = [];
    nodes.forEach(node => {
      sNodes = sNodes.concat(node.getAttribute('containedpostilids').split(','));
    });
    sNodes = uniq(sNodes);
    toJS(chooseItemIds).forEach(id => {
      if (sNodes.indexOf(id) < 0) needDelIds.push(id); 
    });
    needDelIds = uniq(needDelIds);
    return needDelIds;
  }
  canDel = (chooseItemIds = []) => {
    if (this.showRevision) {
      const editor = EditorUtil.getEditor();
      const nodes = editor.document.find('s').toArray();
      let sNodes = [];
      nodes.forEach(node => {
        sNodes = sNodes.concat(node.getAttribute('containedpostilids').split(','));
      });
      if (sNodes.length === 0) return true;
      const needDelIds = this.getNeedDelIds(chooseItemIds);
      if (needDelIds.length === 0) return false;
    }
    return true;
  }

  showPostilList = (hide) => {
    this.show = !hide;
    if(!this.show){
      this.showCloseId = -1;
    }
  }
  findPreviousItem = () => {
    this.findItem(-1);
  }
  findNextItem = () => {
    this.findItem(1);
  }

  findItem = (crossCount) => {
    if (!this.list || !this.list.length) return;
    // let curIndex = toJS(this.list).findIndex((item) => item.id === this.chooseItemId );
    let chooseItemIndex;
    let ranges = EditorUtil.getRanges();
    if (ranges.length === 0) {
      chooseItemIndex = 0;
    } else {
      let range = ranges[0];
      let postil, nodes = EditorUtil.getEditor().document.find('postil[type=\'start\']').toArray();
      if (crossCount > 0) {
        let container = RangeUtil.getStartContainer(range);
        nodes.forEach((node) => {
          if (postil) return;
          let containerSortNum = RangeUtil.sortNode(container, node);
          if (containerSortNum <= 0) {
            postil = node;
          }
        });
      } else {
        let container = RangeUtil.getStartContainer(range);
        // 批注的上一个需要特殊处理
        let prev = container.getPrevious();
        if (prev && typeof prev.getName === 'function' && prev.getName() === 'postil' && prev.getAttribute('type') === 'start') {
          container = prev;
        }
        nodes.reverse().forEach((node) => {
          if (postil) return;
          let containerSortNum = RangeUtil.sortNode(container, node);
          if (containerSortNum > 0) {
            postil = node;
          }
        });
      }
      if (postil) {
        let chooseItemId = postil.getAttribute('dataId');
        chooseItemIndex = toJS(this.list).findIndex((item) => item.id === chooseItemId );
      } else {
        chooseItemIndex = crossCount > 0 ? 0 : this.list.length - 1;
      }
    }
    this.chooseItem(this.list[chooseItemIndex].id);
  }

  /**
   * 从富文本中重新读取批注内容
   */
  refreshPostil = () => {
    let editor = EditorUtil.getEditor(), idMap = {}, list = [],
      nodes = editor.document.find('postil');
    nodes.toArray().forEach((node) => {
      let item = {
        id: node.getAttribute('dataId'),
        datetime: node.getAttribute('datetime'),
        text: node.getAttribute('text'),
        author: node.getAttribute('author'),
        selectedText: node.getAttribute('selectedText'),
      };
      if (idMap[item.id]) return;
      idMap[item.id] = true;
      list.push(item);
    });
    this.list = list;
    // this.list = [...list].sort((first, second) => {
    //   return parseInt(first.id) - parseInt(second.id);
    // });
    this.observeNodeChange(true);
  }

  registerChoosePostil = (func) => {
    isFunction(func) && this.chooseChangeFuncList.push(func);
  }

  creatPostil = this.createPostil

  /**
   * 监听dom树变化以探知批注被删除。
   * 不支持IE9,10.
   */
  observeNodeChange = (isForce) => {
    // 尽量减少Observer的数量，不要重复监听
    if (this.isObserved && !isForce) return;
    let MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;
    let callback = (mutationsList, observer) => {
      for (let mutation of mutationsList) {
        if (mutation.type === 'childList' && mutation.removedNodes.length > 0) {
          mutation.removedNodes.forEach((node) => {
            if (node.tagName === 'POSTIL') {
              this.delPostilNode(node);
            }
          } );
        }
      }
    }
    if (this.currentObserver) {
      this.currentObserver.disconnect();
    }
    let observer = new MutationObserver(callback);
    let config = { attributes: false, childList: true, subtree: true };
    observer.observe(EditorUtil.getEditor().document.$, config);
    this.isObserved = true;
    this.currentObserver = observer;
  }
  onDelPostilNode = (event) => {
    this.notifyPostilNodeDel(event.listenerData.item, event.listenerData.type);
  }
  delPostilNode = (node) => {
    let item = {
      id: node.getAttribute("dataId"),
      text: node.getAttribute("text"),
      datetime: node.getAttribute("datetime"),
      author: node.getAttribute("author"),
      selectedText: node.getAttribute('selectedText'),
    }
    if (!this.showRevision) {
      this.notifyPostilNodeDel(item, node.getAttribute("type"));
    }
  }
  notifyPostilNodeDel = (item, type) => {
    try {
      if (this.showRevision) return; // fix: 修订的时候不删掉批注
      let editor = EditorUtil.getEditor(),
      startNodes = editor.document.find(`postil[type='start'][dataId='${item.id}']`),
        endNodes = editor.document.find(`postil[type='end'][dataId='${item.id}']`);
      // 判断是否已被别的事件处理过
      if (startNodes.count() === endNodes.count()) {
        // 在最后一个字符时，有可能被一起删除掉。
        if (startNodes.count() === 0) {
          this.del([item.id]);
        }
        setTimeout(() => this.trim(item.id), 0);
        return;
      }
      if (this.delAll) return;
      if (this.delPOstilIds.indexOf(item.id.toString()) >= 0) return;
      let ranges = EditorUtil.getRanges();
      // 多个选中状态现在暂不处理
      if (ranges.length > 1 || ranges.length === 0) return;
      let range = ranges[0];
      let id = item.id;
      delete item.id;
      let doc = range.document,
        node = doc.createElement("postil", {attributes: {...item, dataId: id, type}});
      range.optimizeBookmark();
      range.trim();

      let startContainer = range.startContainer, startOffset = range.startOffset, endContainer = range.endContainer, endOffset = range.endOffset;
      let startNode = startContainer.getChild( startOffset ), endNode = endContainer.getChild(endOffset);
      if (type === 'start'){
        // 插入开始节点时，判断是不是结束节点
        if (startNode && startNode.type === CKEDITOR.NODE_ELEMENT && startNode.getName() === 'postil' && startNode.getAttribute("dataId") === id && startNode.getAttribute("type") === 'end') {
          startNode.remove();
        } else {
          startNode ? node.insertBefore( startNode ) : startContainer.append( node );
        }
      } else {
        // 插入结束节点时，判断是不是开始节点
        if (endNode && endNode.type === CKEDITOR.NODE_ELEMENT && endNode.getName() === 'postil' && endNode.getAttribute("dataId") === id && endNode.getAttribute("type") === 'start') {
          endNode.remove();
        } else {
          endNode ? node.insertBefore( endNode ) : endContainer.append( node );
        }
      }
      this.trim(id);
    } catch (e) {
      if (window.console) console.log(e);
    }
  }

  /**
   * 移除相邻的postil节点,并删除不存在的批注
   * @param id
   */
  trim = (id) => {
    if (this.showRevision) return;
    let editor = EditorUtil.getEditor(),
      startNodes = editor.document.find(`postil[type='start'][dataId='${id}']`).toArray(),
      endNodes = editor.document.find(`postil[type='end'][dataId='${id}']`).toArray();
    let i = 0;
    startNodes.forEach((startNode, index) => {
      let endNode = endNodes[index];
      let range = EditorUtil.getEditor().createRange();
      range.setStartAt( startNode, CKEDITOR.POSITION_AFTER_END );
      endNode && range.setEndAt( endNode, CKEDITOR.POSITION_BEFORE_START );
      let nodeList = RangeUtil.getRangeChildren(range);
      let text = nodeList.map(({node}) => EditorUtil.clearEmptyChar(node.getText())).join('');
      if (!text) {
        startNode.remove();
        endNode && endNode.remove();
        i++;
      }
    } );
    if (i === startNodes.length) {
      this.del([id]);
    }
  }
  
  /**
   * 用于外部调用
   * @param id
   */
  doTrim = (ids = []) => {
    this.showRevision = false;
    ids.forEach(id => this.trim(id));
    setTimeout(() => this.showRevision = true, 0);
  }
  setShowRevision = (showRevision) => {
    this.showRevision = showRevision;
  }
  getChooseItemIds = () => {
    let ranges = EditorUtil.getRanges();
    const range = ranges[0];
    const rangeChooseIds = [];
    if (range) {
      range.optimizeBookmark();
      range.trim();
      let startContainer = range.startContainer, startOffset = range.startOffset, endContainer = range.endContainer, endOffset = range.endOffset;
      let startNode = startContainer.getChild(startOffset), endNode = endContainer.getChild(endOffset);
      const nodes = range.document.find('postil[type="start"]').toArray();
      startNode && endNode && nodes && nodes.forEach(v => {
        const sortNumStart = RangeUtil.sortNode(startNode, v);
        const sortNumEnd = RangeUtil.sortNode(endNode, v);
        if (sortNumStart <= 1 && sortNumEnd > 1) rangeChooseIds.push(v.getAttribute('dataid'));
      }); 
    }
    return rangeChooseIds;
  }
  addPostil = (ids) => {
    // 恢复postil标签
    let editor = EditorUtil.getEditor();
    const sNodes = editor.document.find('s').toArray();
    ids.forEach((id) => {
      const startNodes = editor.document.find(`postil[type='start'][dataId='${id}']`).toArray(),
        endNodes = editor.document.find(`postil[type='end'][dataId='${id}']`).toArray();
      const sNode = sNodes.find(node => node.getAttribute('containedpostilids').indexOf(id) >= 0);
      const item = toJS(this.list).find(v => v.id === id);
      let ranges = EditorUtil.getRanges();
      let doc = ranges[0].document;
      if (sNode) {
        if (startNodes.length === 0) sNode.append(doc.createElement("postil", {attributes: {...item, dataId: id, type: 'start'}}));
        if (endNodes.length === 0) sNode.append(doc.createElement("postil", {attributes: {...item, dataId: id, type: 'end'}}));
      }
    });
    this.refreshPostil();
  }
}